﻿/*
 * Copyright (c) 2011, The Chancellor, Masters and Scholars of the University of Oxford
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are 
 * permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list of 
 *   conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this list 
 *   of conditions and the following disclaimer in the documentation and/or other 
 *   materials provided with the distribution.
 *
 * Neither the name of University of Oxford nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific prior 
 * written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
 * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using System.IO;
using Dicom.Data;
using Dicom;
using System.Xml.Linq;
using System.Xml;
using System.Drawing;
using Vreci.Metadata.Dicom;

namespace Vreci.Metadata
{
    public class GenerateFromDicom
    {
        //const string shadow_doc_lib_name = "Hidden_Shadow";
        const string filter_file_metadata = "filter.file.xml";
        const string filter_group_metadata = "filter.group.xml";

        SPWeb web;
        SPDocumentLibrary document_library;
        SPFile dcm_file;
        SPFolder shadow_group_spfolder;
        SPFolder shadow_file_spfolder;

        string dcm_log = "";
        bool dcm_error = false;
        int width;
        int height;

        public GenerateFromDicom(SPWeb web, SPDocumentLibrary document_library, SPFile dcm_file)
        {
            this.web = web;
            this.document_library = document_library;
            this.dcm_file = dcm_file;
            dcm_log = "";
            dcm_error = false;
            this.shadow_file_spfolder = null;
            this.shadow_group_spfolder = null;
        }

        private static string ReplaceSuffix(string file_name, string replacement_suffix)
        {
            return Path.GetFileNameWithoutExtension(file_name) + replacement_suffix;
        }

        public void ProcessDCM()
        {
            dcm_log = "";
            dcm_error = false;

            EnsureShadowFileFolder();

            if (dcm_error) return;

            //Make sure there are filters!
            EnsureMetadataFilters();

            if (dcm_error) return;

            //Try and load it as a DICOM file using the mDCM library
            DicomFileFormat file_format = LoadDicomFile();

            if (dcm_error) return;

            if (file_format.Dataset != null)
            {
                try
                {
                    XDocument dicom_doc = OutputMetadataXmlFile(shadow_file_spfolder,file_format);

                    if (dcm_error) return;

                    OutputPNGFiles(shadow_file_spfolder, file_format);

                    if (dcm_error) return;

                    OutputFilteredMetadata(shadow_file_spfolder,dicom_doc);

                    if (dcm_error) return;

                    OutputFilteredGroupMetadata(shadow_file_spfolder,dicom_doc);
                }
                finally
                {
                    if (dcm_error)
                    {
                        OutputLogFile(document_library.RootFolder);
                    }
                    else
                    {
                        OutputLogFile(shadow_file_spfolder);
                    }
                }
            }
        }

      

        private void EnsureShadowFileFolder()
        {
            try
            {
                //Work out the Shadow Document Library
                SPDocumentLibrary shadow_document_library = web.GetList(web.Url + "/" + HiddenShadowConstants.shadow_doc_lib_name + "/") as SPDocumentLibrary;

                string dcm_path = dcm_file.Url;

                //Work out the shadow file folder address
                shadow_file_spfolder = EnsureDirectoryStructure(shadow_document_library.RootFolder, dcm_path);
                shadow_group_spfolder = shadow_file_spfolder.ParentFolder;

            }
            catch (Exception e)
            {
                dcm_error = true;
                dcm_log += " Exception occured whilst ensuring '" + HiddenShadowConstants.shadow_doc_lib_name + "' exists: " + e.Message + "\n";
                throw e;
            }
        }

        private SPFolder FindDirectoryStructure(SPFolder RootFolder, String DirectoryPath)
        {
            SPFolder currentFolder = RootFolder;
            
                //web.AllowUnsafeUpdates = true;

                //Replace any  '\\' with '/'
                DirectoryPath = DirectoryPath.Replace('\\', '/');

                char[] delimiters = { '/' };

                foreach (string part in DirectoryPath.Split(delimiters))
                {
                    //See if we can find the folder 
                    SPFolder foundSubFolder = FindSubFolder(currentFolder, part);

                    if (foundSubFolder == null)
                    {
                        return null;
                    }

                    //Go down a level
                    currentFolder = foundSubFolder;
                }

            return currentFolder;
        }

        private SPFolder EnsureDirectoryStructure(SPFolder RootFolder, String DirectoryPath)
        {
            SPFolder currentFolder = RootFolder;

            try
            {
                web.AllowUnsafeUpdates = true;

                //Replace any  '\\' with '/'
                DirectoryPath = DirectoryPath.Replace('\\', '/');

                char[] delimiters = { '/' };

                foreach (string part in DirectoryPath.Split(delimiters))
                {
                    //See if we can find the folder 
                    SPFolder foundSubFolder = FindSubFolder(currentFolder, part);

                    if (foundSubFolder == null)
                    {
                        foundSubFolder = currentFolder.SubFolders.Add(part);
                        currentFolder.Update();
                    }

                    //Go down a level
                    currentFolder = foundSubFolder;
                }

            }
            finally
            {
                web.AllowUnsafeUpdates = false;
            }



            return currentFolder;
        }

        private SPFolder FindSubFolder(SPFolder currentFolder, String name)
        {
            foreach (SPFolder subFolder in currentFolder.SubFolders)
            {
                if (subFolder.Name == name)
                {
                    return subFolder;
                }
            }
            return null;
        }

        private static bool Exists(SPFolder sp_folder, string fileName)
        {
            SPWeb web = sp_folder.ParentWeb;
            var url =  sp_folder.Url + "/" + fileName;

            return web.GetFile(url).Exists;
        }

        private void EnsureShadowFolder()
        {
            //Work out where the Shadow Folder should be

        }

        private void EnsureMetadataFilters()
        {
            //Check to see if there are any metadata filters in the directory of the dicom file

            //Group metadata filter
            {
                if (!Exists(shadow_group_spfolder, filter_group_metadata))
                {
                    SaveVreciPropertiesToSPFile(shadow_group_spfolder, DefaultFilterFactory.DefaultFilterGroupMetadata(), filter_group_metadata);
                }
            }

            //File metadata filter
            {
                if (!Exists(shadow_group_spfolder, filter_file_metadata))
                {
                    SaveVreciPropertiesToSPFile(shadow_group_spfolder, DefaultFilterFactory.DefaultFilterFileMetadata(), filter_file_metadata);
                }
            }
        }

        private void OutputFilteredGroupMetadata(SPFolder target_sp_folder, XDocument dicom_doc)
        {
            var all_images_group_curated_metadata_file_name = "curated.group.metadata.xml";

            //See if there is already a group metadata file 'all.images.group.curated.metadata.xml'
            //If not create one using this file.


            var metadata_filter_name = filter_group_metadata;
            XDocument filtered_metadata_doc = null;

            //Load the filter
            Vreci.Metadata.Dicom.DicomFilter filter = LoadMetadataFilter(shadow_group_spfolder, metadata_filter_name);

            //Apply the filter
            if (filter != null)
            {

                //Load existing VreciProperties if it exists. 
                //(This returns a new empty VreciProperties if it doesn't)
                VreciProperties properties = LoadVreciProperties(shadow_group_spfolder, all_images_group_curated_metadata_file_name, false);

                properties = filter.FilterToProperties(dicom_doc, properties);

                //Add extra image properties
                if (properties.FindByReference("http://vreci/dimensions#width") == null)
                {
                    properties.Properties.Add(new VreciPropertyItem()
                    {
                        Hidden = true,
                        Reference = "http://vreci/dimensions#width",
                        Title = "Width",
                        Description = "The width of the image",
                        Value = "" + width
                    });
                }

                //Add extra image properties
                if (properties.FindByReference("http://vreci/dimensions#height") == null)
                {
                    properties.Properties.Add(new VreciPropertyItem()
                    {
                        Hidden = true,
                        Reference = "http://vreci/dimensions#height",
                        Title = "Height",
                        Description = "The height of the image",
                        Value = "" + height
                    });
                }


                filtered_metadata_doc = properties.Write();
            }

            //Save file
            if (filtered_metadata_doc != null)
            {
                SaveXDocumentToSPFile(shadow_group_spfolder, filtered_metadata_doc, all_images_group_curated_metadata_file_name);
            }

        }

        private void OutputFilteredMetadata(SPFolder target_sp_folder, XDocument dicom_doc)
        {
            var metadata_filter_name = filter_file_metadata;
            XDocument filtered_metadata_doc = null;

            //Load the filter
            Vreci.Metadata.Dicom.DicomFilter filter = LoadMetadataFilter(shadow_group_spfolder, metadata_filter_name);

            //Apply the filter
            if (filter != null)
            {
                filtered_metadata_doc = filter.Filter(dicom_doc, new VreciProperties());
            }

            //Save file
            if (filtered_metadata_doc != null)
            {
                var file_name = "curated_metadata.xml";
                SaveXDocumentToSPFile(target_sp_folder, filtered_metadata_doc, file_name);
            }
        }

        private VreciProperties LoadVreciProperties(SPFolder target_sp_folder, string vreci_properties_file_name, bool failIsError)
        {
            VreciProperties vp = new VreciProperties();

            if (Exists(target_sp_folder, vreci_properties_file_name))
            {
                SPFile vreci_properties_spfile = target_sp_folder.Files[vreci_properties_file_name];

                XDocument vreci_properties_xdoc;
                using (MemoryStream filter_stream = new MemoryStream(vreci_properties_spfile.OpenBinary()))
                {
                    using (StreamReader Reader = new StreamReader(filter_stream))
                    {
                        vreci_properties_xdoc = XDocument.Load(Reader);
                        var error_log = vp.Read(vreci_properties_xdoc);
                        if (error_log != null)
                        {
                            dcm_error = true;
                            dcm_log += error_log;
                        }
                    }
                }
            }
            else
            {
                dcm_log += "Unable to find a file called '" + vreci_properties_file_name + "'.\n";
                if (failIsError)
                {
                    dcm_error = true;
                }
            }
            return vp;
        }


        private Vreci.Metadata.Dicom.DicomFilter LoadMetadataFilter(SPFolder target_sp_folder, string vreci_properties_file_name)
        {
            Vreci.Metadata.Dicom.DicomFilter filter = null;

            if (Exists(target_sp_folder, vreci_properties_file_name))
            {
                //See if there is a file called 'metadata.filter.xml
                SPFile metadata_filter_file = target_sp_folder.Files[vreci_properties_file_name];

                XDocument filter_doc;
                using (MemoryStream filter_stream = new MemoryStream(metadata_filter_file.OpenBinary()))
                {
                    using (StreamReader Reader = new StreamReader(filter_stream))
                    {
                        filter_doc = XDocument.Load(Reader);
                        filter = new Vreci.Metadata.Dicom.DicomFilter();
                        var error_log = filter.ReadFilter(filter_doc);
                        if (error_log != null)
                        {
                            dcm_error = true;
                            dcm_log += error_log;
                        }
                    }
                }
            }
            else
            {
                dcm_log += "Unable to find a file called '" + vreci_properties_file_name + "' - so no curated metadata was output\n";
                dcm_error = true;
            }
            return filter;
        }

        private void OutputLogFile(SPFolder target_sp_folder)
        {
            byte[] a = System.Text.Encoding.GetEncoding("iso-8859-1").GetBytes(dcm_log);
            using (MemoryStream memory_stream = new MemoryStream(a))
            {
                var file_name = ReplaceSuffix(dcm_file.Name, (dcm_error ? ".error.txt" : ".log.txt"));
                WriteSPFile(target_sp_folder, memory_stream, file_name);
            }
        }



        private DicomFileFormat LoadDicomFile()
        {
            DicomFileFormat file_format = new DicomFileFormat();

            using (var memStream = new MemoryStream(dcm_file.OpenBinary()))
            {
                file_format.Load(memStream, DicomReadOptions.Default);
            }
            return file_format;
        }

        private XDocument OutputMetadataXmlFile(SPFolder target_sp_folder, DicomFileFormat file_format)
        {
            XDocument xml_document = null;
            try
            {
                dcm_log += "Generate .metadata.xml file\n";
                //Output the DICOM Metadata XML

                //StringBuilder sb = new StringBuilder();
                //file_format.Dataset.Dump(sb, String.Empty, DicomDumpOptions.Default);
                //var RawDump = sb.ToString();

                xml_document = XDicom.ToXML(file_format.Dataset, XDicomOptions.None);
                var file_name = "dicom_metadata.xml";
                SaveXDocumentToSPFile(target_sp_folder, xml_document, file_name);

            }
            catch (Exception e)
            {
                dcm_error = true;
                dcm_log += "  Error: " + e.Message + "\n";
                xml_document = null;
            }

            return xml_document;
        }

        /*
        private void SaveXDocumentToSPFileWithSuffix(SPFolder target_sp_folder, XDocument xml_document, string file_suffix)
        {
            var metadata_file_name = ReplaceSuffix(dcm_file.Name, file_suffix);

            SaveXDocumentToSPFile(target_sp_folder, xml_document, metadata_file_name);
        }
         * */

        private void SaveXDocumentToSPFile(SPFolder target_sp_folder, XDocument xml_document, string metadata_file_name)
        {
            using (var memory_stream = new MemoryStream())
            {
                using (XmlWriter xml_writer = XmlWriter.Create(memory_stream))
                {
                    xml_document.Save(xml_writer);
                }

                dcm_log += "  Target: " + metadata_file_name + "\n";

                WriteSPFile(target_sp_folder, memory_stream, metadata_file_name);
            }
        }

        private void SaveVreciPropertiesToSPFile(SPFolder target_sp_folder, VreciProperties properties, string metadata_file_name)
        {
            SaveXDocumentToSPFile(target_sp_folder, properties.Write(), metadata_file_name);
        }

        private void WriteSPFile(SPFolder target_sp_folder, MemoryStream memory_stream, string file_name)
        {
            bool currentSafety =
                web.AllowUnsafeUpdates;
            try
            {
                web.AllowUnsafeUpdates = true;
                web.Files.Add(web.Url + "/" + target_sp_folder.ToString() + "/" + file_name, memory_stream.ToArray(), true);
            }
            catch (Exception e)
            {
                dcm_error = true;
                dcm_log += " Error whilst writing to file: " + web.Url + "/" + target_sp_folder.ToString() + "/" + file_name + "\n";
                throw e;
            }
            finally
            {
                web.AllowUnsafeUpdates = currentSafety;
            }
        }

        //This is a convertor which works with our current set of images.
        //It may not work with other images - and we expect to come back and
        //fix this when we have more time.
        private Image GetImage(DcmPixelData pixel_data, int frame)
        {

            System.Drawing.Bitmap img = new System.Drawing.Bitmap(pixel_data.ImageWidth, pixel_data.ImageHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            byte[] rawData = pixel_data.GetFrameDataU8(frame);

            int numberOfpixels = pixel_data.ImageWidth * pixel_data.ImageHeight;
            int lengthOfData = rawData.Length;

            //Calculate Maximum

            int Min = 0xFFFF;
            int Max = 0;
            for (int counter0 = 0; counter0 < rawData.Length; counter0 = counter0 + 2)
            {
                int pixelValue = (rawData[counter0] << 8) + rawData[counter0 + 1];

                int topBits = (pixelValue & 7) << 12;
                pixelValue = pixelValue >> 4;
                pixelValue = pixelValue + topBits;

                if (pixelValue > Max)
                {
                    Max = pixelValue;
                }
                if (pixelValue < Min)
                {
                    Min = pixelValue;
                }

            }
            int Range = Max - Min;

            int counter = 0;

            for (int column = 0; column < pixel_data.ImageWidth; column++)
            {
                for (int row = 0; row < pixel_data.ImageHeight; row++)
                {

                    int pixelValue = (rawData[counter] << 8) + rawData[counter + 1];

                    int topBits = (pixelValue & 7) << 12;
                    pixelValue = pixelValue >> 4;
                    pixelValue = pixelValue + topBits;

                    int correctedValue = (pixelValue - Min) * 255 / Range;
                    int greyScale = correctedValue;

                    counter = counter + 2;

                    Color grey = Color.FromArgb(greyScale, greyScale, greyScale);

                    img.SetPixel(row, column, grey);
                }
            }

            return img;
        }



        private System.Drawing.Image GetImage(DcmDataset iDataset)
        {
            try
            {
                DcmPixelData pixeldata = new DcmPixelData(iDataset);
                if (pixeldata.NumberOfFrames == 0)
                {
                    return null;
                }
                else if (pixeldata.NumberOfFrames == 1)
                {
                    return GetImage(pixeldata, 0);
                }
            }
            catch (Exception e)
            {
                dcm_error = true;
                dcm_log += " Error getting image from DICOM file: " + e.Message + "\n";
                throw e;
            }

            return null;
        }

        //Based upon http://snippets.dzone.com/posts/show/4336
        private Image ResizeImage(Image FullsizeImage, int NewWidth, int MaxHeight, bool OnlyResizeIfWider)
        {
            if (OnlyResizeIfWider)
            {
                if (FullsizeImage.Width <= NewWidth)
                {
                    NewWidth = FullsizeImage.Width;
                }
            }

            int NewHeight = FullsizeImage.Height * NewWidth / FullsizeImage.Width;
            if (NewHeight > MaxHeight)
            {
                // Resize with height instead
                NewWidth = FullsizeImage.Width * MaxHeight / FullsizeImage.Height;
                NewHeight = MaxHeight;
            }

            System.Drawing.Image NewImage = FullsizeImage.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero);

            return NewImage;
        }


        private void OutputPNGFiles(SPFolder target_sp_folder, DicomFileFormat file_format)
        {
            try
            {
                dcm_log += "Generate .png files\n";

                //Get the image data
                DcmPixelData pixel_data = null;
                try
                {
                    pixel_data = new DcmPixelData(file_format.Dataset);
                }
                catch (Exception e)
                {
                    dcm_error = true;
                    dcm_log += " Error getting image from DICOM file: " + e.Message + "\n";
                    throw e;
                }

                if (pixel_data != null)
                {
                    //Loop through each of the frames and output it. 
                    //If it is the first frame also output a thumbnail.
                    for (int frame = 0; frame < pixel_data.NumberOfFrames; frame++)
                    {
                        System.Drawing.Image image = GetImage(pixel_data, frame);

                        if (image != null)
                        {
                            width = image.Width;
                            height = image.Height;

                            var image_suffix = "." + frame + ".png";

                            WriteImageToSPFile(target_sp_folder,image, "frame"+image_suffix);

                            EnsureDeepZoom(frame, target_sp_folder, image);
                        }



                        if (frame == 0)
                        {
                            Image thumbnail_image = ResizeImage(image, 48, 48, true);
                            var image_name = "thumbnail.48.png";
                            WriteImageToSPFile(target_sp_folder,thumbnail_image, image_name);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                dcm_error = true;
                dcm_log += "  Error: " + e.Message + "\n";
            }
        }

        private void WriteImageToSPFile(SPFolder target_sp_folder, System.Drawing.Image image, string png_file_name)
        {
            using (var memory_stream = new MemoryStream())
            {
                image.Save(memory_stream, System.Drawing.Imaging.ImageFormat.Png);

                dcm_log += "  Target: " + png_file_name + "\n";

                WriteSPFile(target_sp_folder, memory_stream, png_file_name);

            }
        }

        private void EnsureDeepZoom(int frame_number, SPFolder target_sp_folder, System.Drawing.Image image)
        {
            //Ensure DeepZoom/Frame_<frame_number> folder
            SPFolder DeepZoomFolder = EnsureDirectoryStructure(target_sp_folder, "DeepZoom/Frame_"+frame_number);

            //Add XML File
            XDocument XmlDeepZoom = DeepZoomXml(image.Width, image.Height);
           SaveXDocumentToSPFile(DeepZoomFolder,XmlDeepZoom,"image.xml");

            //Add image_file/0 folder
             SPFolder ZeroFolder = EnsureDirectoryStructure(DeepZoomFolder, "image_files/0");

            //Add '0_0.png' file
              WriteImageToSPFile(ZeroFolder,image, "0_0.png");
            
        }

           public XDocument DeepZoomXml(int width, int height)
        {
               int tile_size = Math.Max(width,height);
               XNamespace ns = "http://schemas.microsoft.com/deepzoom/2009";
            XDocument doc = new XDocument(
         
             new XElement(ns+"Image",
                new XAttribute("TileSize", tile_size),
                new XAttribute("Overlap", "1"),
                 new XAttribute("Format", "png"),
                 new XAttribute("ServerFormat", "Default"),             
                new XElement(ns+"Size",
                   new XAttribute("Width", width),
                   new XAttribute("Height", height)
              )
                )
                );

            return doc;
        }

        /*
           private bool RemovePath(SPFolder Folder, string Path)
           {
               return RemoveIfPossible(Folder, Path, true);
           }

           private bool RemoveIfPossible(SPFolder Folder, string Path, bool Top)
           {
               //Called with the folder A and the path B/C/D or an empty path

               //If the path is empty, then we should simply delete the current folder
               if (Path.Length == 0)
               {
                   try
                   {
                       Folder.Re
                       //Return whether the directory is now deleted
                       return true;
                   }
                   catch
                   {
                       return false;
                   }
               }

               //Take off the first part of the Path (So "B/C/D" gives "B" and "C/D"), ("D" gives "D" and "") 
               string HeadPathPart;
               string TailPath;
               int FirstSlash = Path.IndexOf('/');
               if (FirstSlash < 0)
               {
                   HeadPathPart = Path;
                   TailPath = "";
               }
               else
               {
                   HeadPathPart = Path.Substring(0, FirstSlash);
                   TailPath = Path.Substring(FirstSlash + 1);
               }



               //Go through the sub folders to see if we can find the one named 
               SPFolder FoundSubFolder = null;
               foreach (SPFolder SubFolder in Folder.SubFolders)
               {
                   if (SubFolder.Name == HeadPathPart)
                   {
                       FoundSubFolder = SubFolder;
                       break;
                   }
               }

               //Call remove on the sub folder if possible
               bool DeleteUpPath = true;

               if (FoundSubFolder != null)
               {
                   DeleteUpPath = RemoveIfPossible(FoundSubFolder, TailPath, false);
                   Folder.Update();
               }

               if (DeleteUpPath && !Top)
               {
                   //See if there are any other folders or other files left locally
                   //Folder.ItemCount seems to return the wrong value here 
                   if (Folder.SubFolders.Count + Folder.Files.Count == 0)
                   {
                       try
                       {
                           Folder.Delete();
                           //Return whether the directory is now deleted
                           return true;
                       }
                       catch
                       {
                           return false;
                       }
                   }
                   else
                   {
                       //Lets enumerate the items

                       //String FolderNames = "{";
                       //foreach (SPFolder SubFolder in Folder.SubFolders)
                       //{
                       //    FolderNames += SubFolder.Name + ", ";
                       //}
                       //FolderNames += "}";

                       //String FileNames = "[";
                       //foreach (SPFile SubFile in Folder.Files)
                       //{
                       //    FileNames += SubFile.Name + ", ";
                       //}
                       //FileNames += "]";                 

                       return false;
                   }
               }

               return false;
           }
        */

        public void DeleteSPFolder(SPFolder spFolder) {

            //Delete sub folders
            int fCount = spFolder.SubFolders.Count;
            for (int i = 0; i < fCount; i++)
            {
                //This is zero as each deletion removes an item
                DeleteSPFolder(spFolder.SubFolders[0]);
            }

            //Delete all of the files in the folder
            int iCount = spFolder.Files.Count;

            for (int i = 0; i < iCount; i++)
            {
                //This is zero as each deletion removes an item
                spFolder.Files[0].Delete();
            }

        }


           public void RemoveDCM()
           {
               try
               {
                   //Calculate the file name to remove:
                   try
                   {
                       //Work out the Shadow Document Library
                       SPDocumentLibrary shadow_document_library = web.GetList(web.Url + "/" + HiddenShadowConstants.shadow_doc_lib_name + "/") as SPDocumentLibrary;

                       string dcm_path = dcm_file.Url;

                       //Work out the shadow file folder address
                       shadow_file_spfolder = FindDirectoryStructure(shadow_document_library.RootFolder, dcm_file.Url);
                       shadow_group_spfolder = shadow_file_spfolder.ParentFolder;

                       //Disable event firing - we don't want more ItemDeleting events!
                       

                       //Remove the file itself
                       DeleteSPFolder(shadow_file_spfolder);

                       //If there are no other folders then remove the parent folder
                       if (shadow_file_spfolder.SubFolders.Count == 0)
                       {
                           DeleteSPFolder(shadow_group_spfolder);                         
                       }
                   }
                   catch (Exception e)
                   {
                       dcm_error = true;
                       dcm_log += " Exception occured whilst removing '" + HiddenShadowConstants.shadow_doc_lib_name + "' : " + e.Message + "\n";
                       throw e;
                   }

               }
               finally
               {
                   if (dcm_error)
                   {
                       OutputLogFile(document_library.RootFolder);
                   }
                   
               }
           }

    }
}
